转载自 https://zhuanlan.zhihu.com/p/683330478

以下内容来自腾讯工程师 link

Docker基础篇

云原生技术生态是一个庞大的技术集合,为了便于大家对于Docker、Kubernetes、Prometheus、Envoy、CoreDNS、containerd、Fluentd、Vitess、Jaeger等技术的熟悉,因此整理了云原生二十篇详解相关内容。

第一部分:Docker基础知识

对于容器和虚拟机的对比一些知识,读者看这篇文章之前应该已经有所了解: 首先容器比虚拟机更加轻量,不需要在原来的硬件上再做一层虚拟机化; 其次容器是共享宿主机上的一个进程,启动更快,多个容器之间的通讯性能损失最小;

虚拟机和容器的分层架构可以看下图:

1、Docker引擎

Docker容器架构经过几次演进,随着OCI规范的制定和老的架构问题,现在Docker的架构如上图; (1)Docker Client主要是命令行,比如在终端上执行docker ps -a

(2)Daemon接收CURD指令,主要是与Containerd交互;

(3)Containerd是容器的生命周期管理,主要功能:

(4)containerd-shimrunc启动的中间层;

(5)runc是OCI容器运行时的规范参考实现,runc是从Docker的 libcontainer中迁移而来的,实现了容器启停、资源隔离等功能;

2、容器创建流程

(1)Docker容器启动时候,Docker Daemon并不能直接创建,而是请求 containerd来创建容器;

(2)当containerd收到请求后,也不会直接去操作容器,而是创建containerd-shim的进程,让这个进程去操作容器,指定容器进程是需要一个父进程来做状态收集、维持stdin等fd打开等工作的,假如这个父进程就是containerd,那如果containerd挂掉的话,整个宿主机上所有的容器都得退出,而引入containerd-shim中间层规避这个问题;

(3)创建容器需要做一些namespacescgroups的配置,以及挂载root文件系统等操作,runc就可以按照OCI文档来创建一个符合规范的容器;

(4)真正启动容器是通过containerd-shim去调用runc来启动容器的,runc启动完容器后本身会直接退出,containerd-shim则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给containerd, 并在容器中pid=1的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程;

尝试执行命令 docker container run --name test -it alpine:latest sh ,进入容器:

[root@VM-16-16-centos ~]# docker container run --name test -it alpine:latest sh
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
7264a8db6415: Pull complete
Digest: sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a
Status: Downloaded newer image for alpine:latest

3、镜像

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件,将所有的应用和环境,直接打包为docker镜像,就可以直接运行。

(1)镜像加载原理

(2)镜像如何解决多架构的问题

Docker的方便性决定了镜像需要适配多的架构,为了实现这一特性,镜像仓库服务API支持两种重要的架构,Manifest列表和Manifest。

(3)镜像的命令行

(a)拉取镜像

docker image pull <repository>:<tag>

docker image pull alpine:latest

# 输出
latest: Pulling from library/alpine
Digest: sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a
Status: Image is up to date for alpine:latest
docker.io/library/alpine:latest 

(b)查看镜像

docker image ls --filter=过滤标签

docker images ls

# 输出
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
[root@VM-16-16-centos ~]# docker image ls
REPOSITORY          TAG            IMAGE ID       CREATED         SIZE
alpine              latest         7e01a0d0a1dc   13 days ago     7.34MB
cnrancher/autok3s   v0.6.1         58e8405a4782   9 months ago    254MB
rancher/k3d-tools   5.2.2          ad4072a16136   20 months ago   18.7MB
rancher/k3d-proxy   5.2.2          d0554070bc8c   20 months ago   42.4MB
rancher/k3s         v1.21.7-k3s1   4cbf38ec7da6   20 months ago   174MB 

输出字段解释:

(c)搜索镜像

docker search alpine --filter 过滤标签

docker search alpine --filter 'is-official=true'

# 输出
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
alpine    A minimal Docker image based on Alpine Linux…   10203     [OK] 

(d)镜像详情

docker image inspect ubuntu:latest

docker image inspect ubuntu:latest

# 输出
[
    {
        "Id": "sha256:01f29b872827fa6f9aed0ea0b2ede53aea4ad9d66c7920e81a8db6d1fd9ab7f9",
        "RepoTags": [
            "ubuntu:latest"
        ],
        "RepoDigests": [
            "ubuntu@sha256:ec050c32e4a6085b423d36ecd025c0d3ff00c38ab93a3d71a460ff1c44fa6d77"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2023-08-04T04:53:00.244301537Z",
        "Container": "822f331d59eb72d1131a8a5fcb2b935c8110114c22be26c8572d9881dcff31e0",
        "ContainerConfig": {
            "Hostname": "822f331d59eb",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/bin/bash\"]"
            ],
            "Image": "sha256:22d9eb9a70973f7eb625681c244522dad0bf3b4f8e9ea75977b09d8551364a19",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.opencontainers.image.ref.name": "ubuntu",
                "org.opencontainers.image.version": "22.04"
            }
        },
        "DockerVersion": "20.10.21",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "sha256:22d9eb9a70973f7eb625681c244522dad0bf3b4f8e9ea75977b09d8551364a19",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.opencontainers.image.ref.name": "ubuntu",
                "org.opencontainers.image.version": "22.04"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 77823376,
        "VirtualSize": 77823376,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/7340fd0aaa10bc4e4b4bd202b9b4165e3e3c712af3082cbc606cc5e3e93b53a2/merged",
                "UpperDir": "/var/lib/docker/overlay2/7340fd0aaa10bc4e4b4bd202b9b4165e3e3c712af3082cbc606cc5e3e93b53a2/diff",
                "WorkDir": "/var/lib/docker/overlay2/7340fd0aaa10bc4e4b4bd202b9b4165e3e3c712af3082cbc606cc5e3e93b53a2/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:bce45ce613d34bff6a3404a4c2d56a5f72640f804c3d0bd67e2cf0bf97cb950c"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
] 

以上是包含一个镜像所有的信息,包括CPU架构,容器命令行等信息。

(e)保存或加载镜像文件

保存:docker image save -o [镜像tar文件] [镜像ID] 加载:docker load -i [镜像tar文件]

[root@VM-16-16-centos ~]# docker image save -o alpine.tar 7e01a0d0a1dc
[root@VM-16-16-centos ~]# ls
alpine.tar  a.out  core.365609  test.cc

[root@VM-16-16-centos ~]# docker load -i  alpine.tar
Loaded image ID: sha256:7e01a0d0a1dcd9e539f8e9bbd80106d59efbdf97293b3d38f5d7a34501526cdb 

(f)删除镜像

docker image rm [镜像ID]

[root@VM-16-16-centos ~]# docker image rm 7e01a0d0a1dc -f
Untagged: alpine:latest
Untagged: alpine@sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a
Deleted: sha256:7e01a0d0a1dcd9e539f8e9bbd80106d59efbdf97293b3d38f5d7a34501526cdb 

4、容器与容器化

前面已经提到过,容器是共享操作系统内核,所以容器比虚拟机的开销更小,往往一台物理机上可以运行数千个容器,而且在后台开发中,容器使用方便,已经成为服务部署的标配,那下面我们来了解一下容器和容器化。

(1)启动一个简单的容器

docker run -it ubuntu:latest /bin/bash

# 输出
[root@node1 ~]# docker run -it ubuntu:latest /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
7b1a6ab2e44d: Pull complete 
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:latest
root@41b22410e6bc:/#

(2)容器的生命周期

(3)快速清理

docker rm $(docker container ls -aq) -f

# 输出
[root@node1 ~]# docker rm $(docker container ls -aq) -f
41b22410e6bc
d280d169f140
2d0ab5f14a5f
654ee324b7ac
2d0694c9e06a
a78be97042fd
b9e7e71c07eb
6a1c7e736b2a

(4)应用容器化流程

(5)Dockerfile

FROM apline
LABEL maintainer="xxx@gmail.com"
RUN apk add --update nodejs nodejs-npm
COPY . /src
WORKDIR /src
RUN npm install
EXPOSE 8080
ENTRYPOINT ["node", "./app.js"]

以上是一个Dockerfile文件,字段解释:

(6)Dockerfile镜像

(7)多阶段构建

在Docker 17.05版本以后,提供了多阶段构建,什么是多阶段构建呢?

FROM node:latest AS storefront
WORKDIR /usr/src/app/react-app
COPY react-app .
RUN npm install
RUN npm run build

FROM server:latest AS appserver
WORKDIR /usr/src/app/appserver
...

FROM production:latest AS production
WORKDIR /static
COPY --from=storefront /usr/src/app/react-app/build/ .
WORKDIR /app
COPY --from=appserver /usr/src/app/appserver/build/ .
ENTRYPOINT ["./startup", "--config=..."]
CMD ["xxxx"]

以上是一个多阶段构建的Dockerfile文件,字段解释:

(8)最佳实践

5、Docker Compose

Docker Compose vs. Dockerfile with Code Examples

(1)Docker-Compose文件

version: '3.4'

services:
  webmvc:
    image: eshop/webmvc
    environment:
      - CatalogUrl=http://catalog-api
      - OrderingUrl=http://ordering-api
      - BasketUrl=http://basket-api
    ports:
      - "5100:80"
    depends_on:
      - catalog-api
      - ordering-api
      - basket-api

  catalog-api:
    image: eshop/catalog-api
    environment:
      - ConnectionString=Server=sqldata;Initial Catalog=CatalogData;User Id=sa;Password=[PLACEHOLDER]
    expose:
      - "80"
    ports:
      - "5101:80"
    #extra hosts can be used for standalone SQL Server or services at the dev PC
    extra_hosts:
      - "CESARDLSURFBOOK:10.0.75.1"
    depends_on:
      - sqldata

  ordering-api:
    image: eshop/ordering-api
    environment:
      - ConnectionString=Server=sqldata;Database=Services.OrderingDb;User Id=sa;Password=[PLACEHOLDER]
    ports:
      - "5102:80"
    #extra hosts can be used for standalone SQL Server or services at the dev PC
    extra_hosts:
      - "CESARDLSURFBOOK:10.0.75.1"
    depends_on:
      - sqldata

  basket-api:
    image: eshop/basket-api
    environment:
      - ConnectionString=sqldata
    ports:
      - "5103:80"
    depends_on:
      - sqldata

  sqldata:
    environment:
      - SA_PASSWORD=[PLACEHOLDER]
      - ACCEPT_EULA=Y
    ports:
      - "5434:1433"

  basketdata:
    image: redis

上述语法说明:

(2)Docker-Compose命令

6、容器的持久化数据

容器中有持久化数据和非持久化数据,两种在实用场景下有很多,其中非持久化是自动创建,从属于容器,生命周期与容器相同,如果希望数据在容器中保留,可以将需要的数据存储在卷上。

(1)创建存储卷

使用命令创建存储卷 docker volume create myvol,然后可以通过 docker volume inspect myvol 获得输出:

[
    {
        "CreatedAt": "2023-09-02T08:03:38+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myvol/_data",
        "Name": "myvol",
        "Options": {},
        "Scope": "local"
    }
]

【后台技术】Docker基础篇和网络篇
热榜最高第1名
linkxzhou2023年10月09日
宽屏
3232
7
274

AI摘要

| 导语IEG增值服务部 - 技术藏经阁 :秉承增值服务部核心的创新向上的理念,利用KM知识分享开放平台来沉淀和输出部门内的核心技术相关能力。构建与公司团共同交流、共同成长的开放性知识K吧。 更多文章请点击:http://km.oa.com/group/34294

目录
Docker基础篇
第一部分:Docker基础知识
1、Docker引擎
2、容器创建流程
2、镜像
3、容器与容器化
4、Docker Compose
4、容器的持久化数据
第二部分:Docker Swarm
1、Docker Swarm原理
2、Docker Swarm基本命令
Docker网络篇
第一部分:Docker网络
1、详解
第二部分:网桥和Overlay详解
1、网桥(Bridge)
2、Overlay
第三部分:服务发现和Ingress
1、服务发现
2、Ingress
参考最近在我的公众号《周末程序猿》整理云原生二十篇,顺便把文章搬过来,有兴趣的可以读读或者关注。
Docker基础篇
云原生技术生态是一个庞大的技术集合,为了便于大家对于Docker、Kubernetes、Prometheus、Envoy、CoreDNS、containerd、Fluentd、Vitess、Jaeger等技术的熟悉,因此整理了云原生二十篇详解相关内容。
第一部分:Docker基础知识
对于容器和虚拟机的对比一些知识,读者看这篇文章之前应该已经有所了解: 首先容器比虚拟机更加轻量,不需要在原来的硬件上再做一层虚拟机化; 其次容器是共享宿主机上的一个进程,启动更快,多个容器之间的通讯性能损失最小;
虚拟机和容器的分层架构可以看下图:

1、Docker引擎

Docker容器架构经过几次演进,随着OCI规范的制定和老的架构问题,现在Docker的架构如上图; (1)Docker Client主要是命令行,比如在终端上执行docker ps -a
(2)Daemon接收CURD指令,主要是与Containerd交互;
(3)Containerd是容器的生命周期管理,主要功能:

(4)containerd-shimrunc启动的中间层;
(5)runc是OCI容器运行时的规范参考实现,runc是从Docker的 libcontainer中迁移而来的,实现了容器启停、资源隔离等功能;
2、容器创建流程
(1)Docker容器启动时候,Docker Daemon并不能直接创建,而是请求 containerd来创建容器;
(2)当containerd收到请求后,也不会直接去操作容器,而是创建containerd-shim的进程,让这个进程去操作容器,指定容器进程是需要一个父进程来做状态收集、维持stdin等fd打开等工作的,假如这个父进程就是containerd,那如果containerd挂掉的话,整个宿主机上所有的容器都得退出,而引入containerd-shim中间层规避这个问题;
(3)创建容器需要做一些namespacescgroups的配置,以及挂载root文件系统等操作,runc就可以按照OCI文档来创建一个符合规范的容器;
(4)真正启动容器是通过containerd-shim去调用runc来启动容器的,runc启动完容器后本身会直接退出,containerd-shim则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给containerd, 并在容器中pid=1的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程;
尝试执行命令 docker container run --name test -it alpine:latest sh ,进入容器:
[root@VM-16-16-centos ~]# docker container run --name test -it alpine:latest sh Unable to find image 'alpine:latest' locally latest: Pulling from library/alpine 7264a8db6415: Pull complete Digest: sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a Status: Downloaded newer image for alpine:latest
2、镜像
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件,将所有的应用和环境,直接打包为docker镜像,就可以直接运行。
(1)镜像加载原理

(2)镜像如何解决多架构的问题
Docker的方便性决定了镜像需要适配多的架构,为了实现这一特性,镜像仓库服务API支持两种重要的架构,Manifest列表和Manifest。

(3)镜像的命令行
(a)拉取镜像
docker image pull <repository>:<tag>
docker image pull alpine:latest # 输出 latest: Pulling from library/alpine Digest: sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a Status: Image is up to date for alpine:latest http://docker.io/library/alpine:latest
(b)查看镜像
docker image ls --filter=过滤标签
docker images ls # 输出 REPOSITORY TAG IMAGE ID CREATED SIZE [root@VM-16-16-centos ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest 7e01a0d0a1dc 13 days ago 7.34MB cnrancher/autok3s v0.6.1 58e8405a4782 9 months ago 254MB rancher/k3d-tools 5.2.2 ad4072a16136 20 months ago 18.7MB rancher/k3d-proxy 5.2.2 d0554070bc8c 20 months ago 42.4MB rancher/k3s v1.21.7-k3s1 4cbf38ec7da6 20 months ago 174MB
输出字段解释:

(c)搜索镜像
docker search alpine --filter 过滤标签
docker search alpine --filter 'is-official=true' # 输出 NAME DESCRIPTION STARS OFFICIAL AUTOMATED alpine A minimal Docker image based on Alpine Linux… 10203 [OK]
(d)镜像详情
docker image inspect ubuntu:latest
docker image inspect ubuntu:latest # 输出 [ { "Id": "sha256:01f29b872827fa6f9aed0ea0b2ede53aea4ad9d66c7920e81a8db6d1fd9ab7f9", "RepoTags": [ "ubuntu:latest" ], "RepoDigests": [ "ubuntu@sha256:ec050c32e4a6085b423d36ecd025c0d3ff00c38ab93a3d71a460ff1c44fa6d77" ], "Parent": "", "Comment": "", "Created": "2023-08-04T04:53:00.244301537Z", "Container": "822f331d59eb72d1131a8a5fcb2b935c8110114c22be26c8572d9881dcff31e0", "ContainerConfig": { "Hostname": "822f331d59eb", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"/bin/bash\"]" ], "Image": "sha256:22d9eb9a70973f7eb625681c244522dad0bf3b4f8e9ea75977b09d8551364a19", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "org.opencontainers.image.ref.name": "ubuntu", "org.opencontainers.image.version": "22.04" } }, "DockerVersion": "20.10.21", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "sha256:22d9eb9a70973f7eb625681c244522dad0bf3b4f8e9ea75977b09d8551364a19", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "org.opencontainers.image.ref.name": "ubuntu", "org.opencontainers.image.version": "22.04" } }, "Architecture": "amd64", "Os": "linux", "Size": 77823376, "VirtualSize": 77823376, "GraphDriver": { "Data": { "MergedDir": "/var/lib/docker/overlay2/7340fd0aaa10bc4e4b4bd202b9b4165e3e3c712af3082cbc606cc5e3e93b53a2/merged", "UpperDir": "/var/lib/docker/overlay2/7340fd0aaa10bc4e4b4bd202b9b4165e3e3c712af3082cbc606cc5e3e93b53a2/diff", "WorkDir": "/var/lib/docker/overlay2/7340fd0aaa10bc4e4b4bd202b9b4165e3e3c712af3082cbc606cc5e3e93b53a2/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:bce45ce613d34bff6a3404a4c2d56a5f72640f804c3d0bd67e2cf0bf97cb950c" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ]
以上是包含一个镜像所有的信息,包括CPU架构,容器命令行等信息。
(e)保存或加载镜像文件
保存:docker image save -o [镜像tar文件] [镜像ID] 加载:docker load -i [镜像tar文件]
[root@VM-16-16-centos ~]# docker image save -o alpine.tar 7e01a0d0a1dc [root@VM-16-16-centos ~]# ls alpine.tar a.out core.365609 http://test.cc [root@VM-16-16-centos ~]# docker load -i alpine.tar Loaded image ID: sha256:7e01a0d0a1dcd9e539f8e9bbd80106d59efbdf97293b3d38f5d7a34501526cdb
(f)删除镜像
docker image rm [镜像ID]
[root@VM-16-16-centos ~]# docker image rm 7e01a0d0a1dc -f Untagged: alpine:latest Untagged: alpine@sha256:7144f7bab3d4c2648d7e59409f15ec52a18006a128c733fcff20d3a4a54ba44a Deleted: sha256:7e01a0d0a1dcd9e539f8e9bbd80106d59efbdf97293b3d38f5d7a34501526cdb
3、容器与容器化
前面已经提到过,容器是共享操作系统内核,所以容器比虚拟机的开销更小,往往一台物理机上可以运行数千个容器,而且在后台开发中,容器使用方便,已经成为服务部署的标配,那下面我们来了解一下容器和容器化。
(1)启动一个简单的容器
docker run -it ubuntu:latest /bin/bash # 输出 [root@node1 ~]# docker run -it ubuntu:latest /bin/bash Unable to find image 'ubuntu:latest' locally latest: Pulling from library/ubuntu 7b1a6ab2e44d: Pull complete Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322 Status: Downloaded newer image for ubuntu:latest root@41b22410e6bc:/#
(2)容器的生命周期

(3)快速清理
docker rm $(docker container ls -aq) -f # 输出 [root@node1 ~]# docker rm $(docker container ls -aq) -f 41b22410e6bc d280d169f140 2d0ab5f14a5f 654ee324b7ac 2d0694c9e06a a78be97042fd b9e7e71c07eb 6a1c7e736b2a
(4)应用容器化流程

(5)Dockerfile
FROM apline LABEL maintainer="xxx@gmail.com" RUN apk add --update nodejs nodejs-npm COPY . /src WORKDIR /src RUN npm install EXPOSE 8080 ENTRYPOINT ["node", "./app.js"]
以上是一个Dockerfile文件,字段解释:

(6)Dockerfile镜像

(7)多阶段构建
在Docker 17.05版本以后,提供了多阶段构建,什么是多阶段构建呢?
FROM node:latest AS storefront WORKDIR /usr/src/app/react-app COPY react-app . RUN npm install RUN npm run build FROM server:latest AS appserver WORKDIR /usr/src/app/appserver ... FROM production:latest AS production WORKDIR /static COPY --from=storefront /usr/src/app/react-app/build/ . WORKDIR /app COPY --from=appserver /usr/src/app/appserver/build/ . ENTRYPOINT ["./startup", "--config=..."] CMD ["xxxx"]
以上是一个多阶段构建的Dockerfile文件,字段解释:

(8)最佳实践

4、Docker Compose
(1)Docker-Compose文件
version: '3.4' services: webmvc: image: eshop/webmvc environment: - CatalogUrl=http://catalog-api - OrderingUrl=http://ordering-api - BasketUrl=http://basket-api ports: - "5100:80" depends_on: - catalog-api - ordering-api - basket-api catalog-api: image: eshop/catalog-api environment: - ConnectionString=Server=sqldata;Initial Catalog=CatalogData;User Id=sa;Password=[PLACEHOLDER] expose: - "80" ports: - "5101:80" #extra hosts can be used for standalone SQL Server or services at the dev PC extra_hosts: - "CESARDLSURFBOOK:10.0.75.1" depends_on: - sqldata ordering-api: image: eshop/ordering-api environment: - ConnectionString=Server=sqldata;Database=Services.OrderingDb;User Id=sa;Password=[PLACEHOLDER] ports: - "5102:80" #extra hosts can be used for standalone SQL Server or services at the dev PC extra_hosts: - "CESARDLSURFBOOK:10.0.75.1" depends_on: - sqldata basket-api: image: eshop/basket-api environment: - ConnectionString=sqldata ports: - "5103:80" depends_on: - sqldata sqldata: environment: - SA_PASSWORD=[PLACEHOLDER] - ACCEPT_EULA=Y ports: - "5434:1433" basketdata: image: redis
上述语法说明:

(2)Docker-Compose命令

4、容器的持久化数据
容器中有持久化数据和非持久化数据,两种在实用场景下有很多,其中非持久化是自动创建,从属于容器,生命周期与容器相同,如果希望数据在容器中保留,可以将需要的数据存储在卷上。

(1)创建存储卷

使用命令创建存储卷 docker volume create myvol,然后可以通过 docker volume inspect myvol 获得输出:

[
    {
        "CreatedAt": "2023-09-02T08:03:38+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myvol/_data",
        "Name": "myvol",
        "Options": {},
        "Scope": "local"
    }
]

其中存储卷支持几种访问类型,包括块存储,文件存储,对象存储

(2)删除存储卷

(3)挂载卷

使用命令挂载卷 docker run -it -name voltest --mount source=myvol,target=/vol alpine,可以通过 docker volume ls查看:

[root@node1 ~]# docker volume ls
DRIVER              VOLUME NAME
local               myvol

Docker volume 支持挂载传播的配置Propagation,比如docker run –d -v /home:/data:slave nginx表示主机/home下面挂载的目录,在容器/data下面可用,反之不行,其中可选配置如下:

(4)集群节点间共享存储

集群间共享存储最大的问题就是数据一致性,比如容器A在共享卷中更新了部分数据,但是数据实际写入了本地缓存并未同步卷中,同时容器B也在共享卷中更新了部分数据,并同步到了卷中,这时卷中的数据必然存在冲突,如何解决?一种方案是通过应用层解决,另一种方案是通过第三方存储卷,比如NFS,Ceph或者S3等,这里在后续的文章中会继续介绍。

第二部分:Docker Swarm

Docker Swarm与K8S相比使用场景越来越少,但是对于小集群而言,Docker Swarm还是有一些便利的地方,因此在此做一些简单的介绍。

1、Docker Swarm原理

Docker Swarm分为Manager和Worker节点,Manager节点是负责整个集群的控制面,进行集群的监控,分发任务等操作;Worker节点接收Manager节点的任务并执行,其中整个集群的配置和状态信息都存储在etcd数据库中,其大概的架构图如下:

2、Docker Swarm基本命令

(1)启动

命令:docker swarm init --advertise-addr 9.134.229.3:2377 --listen-addr 9.134.229.3:2399 输出:

Swarm initialized: current node (l5ul5q41m7n4vuxhp8bge5lcv) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-26n7usg20hde1uxz4fo7z4baqvfv5y6i12oznvywrgc56el40c-3pvhlj63uxsz0rkw9cb5jd2gy 9.134.229.3:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

(2)加入节点

命令:docker swarm join --token SWMTKN-1-26n7usg20hde1uxz4fo7z4baqvfv5y6i12oznvywrgc56el40c-3pvhlj63uxsz0rkw9cb5jd2gy 9.134.229.3:2377 输出:

[root@VM-229-3-centos ~]# docker node ls
ID                            HOSTNAME               STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
scj0t5d3th79tyd1cw05dqv3o *   VM-229-3-centos        Ready     Active         Leader           23.0.1
tbpeirjj8nj2egnvkec91oewt     VM-230-108-tencentos   Ready     Active                          23.0.1

(3)高可用

Swarm实现了一种主从方式的多管理节点的HA,但是仅有一个节点处于活动状态。 处于活动状态的管理节点被称为"主节点",而主节点也是唯一一个会对Swarm发送控制命令的节点,同时只有主节点才会变更配置,或者发送任务到工作节点。 如果一个备用管理节点接收到Swarm命令,则它会将其转发到其他主节点。 关于Swarm高可用的最佳实践原则:

(4)扩容和滚动升级

Swarm中有类似K8S中的service概念,只要在service中配置了端口映射,所有节点都会自动生成映射,将请求转发到运行有服务的副本节点中。

参考

(1)https://zhuanlan.zhihu.com/p/558785823

(2)https://www.cnblogs.com/oscar2960/p/16536891.html

(3)https://www.jianshu.com/p/e3a87c76aab4?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

下期将继续分享【后台技术】Docker网络篇,敬请期待~

欢迎点赞分享,搜索关注【鹅厂架构师】公众号,一起探索更多业界领先产品技术。

请 Ta 喝咖啡 ☕️